package org.study.rule.boot.engine.util;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Range;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.study.rule.boot.model.AlarmConfig;
import org.study.rule.boot.model.AlarmInfo;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 作用描述
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2024年08月25日
 */
@Slf4j
@UtilityClass
public class AlarmInfoUtils {
    /**
     * 根据告警条件、实际值判断是否触发告警。
     * 数据都是转为BigDecimal后再进行比较，因此只支持数值型告警配置
     *
     * @param alarmConfig 告警配置信息
     * @param value       实际值
     */
    public boolean hasAlarm(AlarmConfig alarmConfig, BigDecimal value) {
        log.info("当前告警配置：{}，实际值：{}", JSON.toJSONString(alarmConfig), value);
        boolean isAlarm = false;
        String config = alarmConfig.getConfig();
        if (StringUtils.isNotBlank(config)) {
            JSONObject jsonObject = JSONUtil.parseObj(config);
            String operator = jsonObject.getStr("operator");
            switch (operator.toLowerCase()) {
                case "gt":
                    String gtParam1 = jsonObject.getStr("param1");
                    // isAlarm = Range.greaterThan(new BigDecimal(gtParam1)).contains(value);
                    isAlarm = value.compareTo(new BigDecimal(gtParam1)) > 0;
                    break;
                case "ge":
                    String geParam1 = jsonObject.getStr("param1");
                    // isAlarm = Range.atLeast(new BigDecimal(geParam1)).contains(value);
                    isAlarm = value.compareTo(new BigDecimal(geParam1)) >= 0;
                    break;
                case "lt":
                    String ltParam1 = jsonObject.getStr("param1");
                    // isAlarm = Range.lessThan(new BigDecimal(ltParam1)).contains(value);
                    isAlarm = value.compareTo(new BigDecimal(ltParam1)) < 0;
                    break;
                case "le":
                    String leParam1 = jsonObject.getStr("param1");
                    // isAlarm = Range.atMost(new BigDecimal(leParam1)).contains(value);
                    isAlarm = value.compareTo(new BigDecimal(leParam1)) <= 0;
                    break;
                case "eq":
                    String eqParam1 = jsonObject.getStr("param1");
                    isAlarm = value.compareTo(new BigDecimal(eqParam1)) == 0;
                    break;
                case "ne":
                    String neParam1 = jsonObject.getStr("param1");
                    isAlarm = value.compareTo(new BigDecimal(neParam1)) != 0;
                    break;
                case "in":
                    String inParam1 = jsonObject.getStr("param1");
                    String[] inSplit = inParam1.split(",");
                    for (String in : inSplit) {
                        if (value.compareTo(new BigDecimal(in.trim())) == 0) {
                            isAlarm = true;
                            break;
                        }
                    }
                    break;
                case "not_in":
                    String notInParam1 = jsonObject.getStr("param1");
                    String[] notInSplit = notInParam1.split(",");
                    boolean isNotIn = true;
                    for (String notIn : notInSplit) {
                        if (value.compareTo(new BigDecimal(notIn.trim())) == 0) {
                            isNotIn = false;
                            break;
                        }
                    }
                    if (isNotIn) {
                        isAlarm = true;
                    }
                    break;
                case "between":
                    String betweenParam1 = jsonObject.getStr("param1");
                    String betweenParam2 = jsonObject.getStr("param2");
                    // isAlarm = Range.open(new BigDecimal(betweenParam1), new BigDecimal(betweenParam2)).contains(value);
                    isAlarm = Range.closed(new BigDecimal(betweenParam1), new BigDecimal(betweenParam2)).contains(value);
                    break;
                case "not_between":
                    String notBetweenParam1 = jsonObject.getStr("param1");
                    String notBetweenParam2 = jsonObject.getStr("param2");
                    // isAlarm = !Range.open(new BigDecimal(notBetweenParam1), new BigDecimal(notBetweenParam2)).contains(value);
                    isAlarm = !Range.closed(new BigDecimal(notBetweenParam1), new BigDecimal(notBetweenParam2)).contains(value);
                    break;
                default:
                    log.error("暂时不支持该告警规则的解析：{}", JSON.toJSONString(alarmConfig));
                    break;
            }
        }
        return isAlarm;
    }

    /**
     * 根据告警条件、实际值判断是否触发告警，若有告警，则生成一条告警信息
     *
     * @param alarmConfig 告警配置信息
     * @param value       实际值
     */
    public AlarmInfo buildAlarmInfo(AlarmConfig alarmConfig, BigDecimal value) {
        log.info("当前告警配置：{}，实际值：{}", JSON.toJSONString(alarmConfig), value);
        AlarmInfo alarmInfo = null;
        if (hasAlarm(alarmConfig, value)) {
            alarmInfo = AlarmInfo.builder()
                    .name(alarmConfig.getName())
                    .level(alarmConfig.getLevel())
                    .deviceId(alarmConfig.getDeviceId())
                    .pointId(alarmConfig.getPointId())
                    .config(alarmConfig.getConfig())
                    .value(value.toPlainString())
                    .datetime(LocalDateTime.now())
                    .status(0)
                    .build();
            log.info("生成的告警信息为：{}", JSON.toJSONString(alarmInfo));
        } else {
            log.info("无告警");
        }
        return alarmInfo;
    }
}
